//  把包名改成你项目里原来的 —— 例如：package no.nordicsemi.android.nrfmesh.database;
package no.nordicsemi.android.nrfmesh.database;

import android.content.Context;
import android.database.Cursor;

import androidx.annotation.NonNull;
import androidx.room.Database;
import androidx.room.Room;
import androidx.room.RoomDatabase;
import androidx.room.TypeConverters;
import androidx.room.migration.Migration;
import androidx.sqlite.db.SupportSQLiteDatabase;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import no.nordicsemi.android.nrfmesh.database.dao.LocalAccountDao;
import no.nordicsemi.android.nrfmesh.database.dao.ReceivedProfileDao;
import no.nordicsemi.android.nrfmesh.database.dao.SentProfileDao;
import no.nordicsemi.android.nrfmesh.database.dao.StimProfileDao;
import no.nordicsemi.android.nrfmesh.database.dao.LogRecordDao;
import no.nordicsemi.android.nrfmesh.database.entity.LocalAccount;
import no.nordicsemi.android.nrfmesh.database.entity.LogRecord;
import no.nordicsemi.android.nrfmesh.database.entity.ReceivedProfile;
import no.nordicsemi.android.nrfmesh.database.entity.SentProfile;
import no.nordicsemi.android.nrfmesh.database.entity.StimProfile;

@Database(
        entities = {
                LocalAccount.class,
                LogRecord.class,
                StimProfile.class,
                SentProfile.class,
                ReceivedProfile.class
        },
        version = AppDatabase.DATABASE_VERSION,
        exportSchema = false
)
@TypeConverters({DateConverter.class})
public abstract class AppDatabase extends RoomDatabase {

    public static final int DATABASE_VERSION = 2;
    private static final String DB_NAME = "stim_profile_database";

    private static final ExecutorService DB_EXECUTOR = Executors.newSingleThreadExecutor();
    public static ExecutorService io() { return DB_EXECUTOR; }

    public abstract LocalAccountDao localAccountDao();
    public abstract StimProfileDao  stimProfileDao();
    public abstract SentProfileDao  sentProfileDao();
    public abstract ReceivedProfileDao receivedProfileDao();
    public abstract LogRecordDao logRecordDao();

    private static volatile AppDatabase INSTANCE;

    public static AppDatabase getInstance(Context context) {
        if (INSTANCE == null) {
            synchronized (AppDatabase.class) {
                if (INSTANCE == null) {
                    RoomDatabase.Builder<AppDatabase> builder =
                            Room.databaseBuilder(
                                            context.getApplicationContext(),
                                            AppDatabase.class,
                                            DB_NAME
                                    )
                                    .addMigrations(MIGRATION_1_2)
                                    .setQueryExecutor(DB_EXECUTOR)
                                    .setTransactionExecutor(DB_EXECUTOR);

                    // 如需调试期允许主线程 I/O，可临时放开：
                    // if (no.nordicsemi.android.nrfmesh.BuildConfig.DEBUG) {
                    //     builder = builder.allowMainThreadQueries();
                    // }

                    INSTANCE = builder.build();
                }
            }
        }
        return INSTANCE;
    }

    public static final Migration MIGRATION_1_2 = new Migration(1, 2) {
        @Override public void migrate(@NonNull SupportSQLiteDatabase db) {
            migrateLocalAccounts(db);
            migrateStimProfiles(db);
        }
    };

    private static void migrateLocalAccounts(SupportSQLiteDatabase db) {
        final String T_NEW = "local_accounts";
        final String T_OLD = "LocalAccount"; // 旧表名（如直接按类名存过）

        boolean newExists = tableExists(db, T_NEW);
        boolean oldExists = tableExists(db, T_OLD);

        if (!newExists && !oldExists) {
            createLocalAccountsTable(db, T_NEW);
        } else if (oldExists && !newExists) {
            createLocalAccountsTable(db, T_NEW);

            StringBuilder colsNew = new StringBuilder();
            StringBuilder colsSrc = new StringBuilder();
            appendCopyColumn(db, T_OLD, colsNew, colsSrc, "userId",           "userId",           "'UNKNOWN'");
            appendCopyColumn(db, T_OLD, colsNew, colsSrc, "displayName",      "displayName",      "NULL");
            appendCopyColumn(db, T_OLD, colsNew, colsSrc, "rememberOnDevice", "rememberOnDevice", "1");
            appendCopyColumn(db, T_OLD, colsNew, colsSrc, "autoLogin",        "autoLogin",        "0");
            appendCopyColumn(db, T_OLD, colsNew, colsSrc, "lastLoginAt",      "lastLoginAt",      "0");

            db.execSQL("INSERT INTO `" + T_NEW + "` (" + colsNew + ") " +
                    "SELECT " + colsSrc + " FROM `"+T_OLD+"`");
            db.execSQL("DROP TABLE `" + T_OLD + "`");
        } else {
            ensureColumn(db, T_NEW, "displayName",      "TEXT",    null);
            ensureColumn(db, T_NEW, "rememberOnDevice", "INTEGER", "1");
            ensureColumn(db, T_NEW, "autoLogin",        "INTEGER", "0");
            ensureColumn(db, T_NEW, "lastLoginAt",      "INTEGER", "0");
        }
    }

    private static void createLocalAccountsTable(SupportSQLiteDatabase db, String table) {
        db.execSQL(
                "CREATE TABLE IF NOT EXISTS `" + table + "` (" +
                        "`userId` TEXT NOT NULL, " +
                        "`displayName` TEXT, " +
                        "`rememberOnDevice` INTEGER NOT NULL DEFAULT 1, " +
                        "`autoLogin` INTEGER NOT NULL DEFAULT 0, " +
                        "`lastLoginAt` INTEGER NOT NULL DEFAULT 0, " +
                        "PRIMARY KEY(`userId`))"
        );
    }

    private static void migrateStimProfiles(SupportSQLiteDatabase db) {
        final String T_NEW = "stimulation_profiles";
        final String[] OLD_CANDIDATES = new String[] {
                "StimProfile", "StimProfiles", "stim_profiles", "stimulation_profile"
        };

        boolean newExists = tableExists(db, T_NEW);
        String oldFound = null;
        for (String cand : OLD_CANDIDATES) {
            if (tableExists(db, cand)) { oldFound = cand; break; }
        }

        if (!newExists && oldFound == null) {
            createStimProfilesTable(db, T_NEW);
            return;
        }

        if (!newExists && oldFound != null) {
            createStimProfilesTable(db, T_NEW);

            StringBuilder colsNew = new StringBuilder();
            StringBuilder colsSrc = new StringBuilder();
            appendCopyColumn(db, oldFound, colsNew, colsSrc, "id",             "id",             "NULL");
            appendCopyColumn(db, oldFound, colsNew, colsSrc, "name",           "name",           "NULL");
            appendCopyColumn(db, oldFound, colsNew, colsSrc, "waveform",       "waveform",       "NULL");
            appendCopyColumn(db, oldFound, colsNew, colsSrc, "block",          "block",          "0");
            appendCopyColumn(db, oldFound, colsNew, colsSrc, "current",        "current",        "0");
            appendCopyColumn(db, oldFound, colsNew, colsSrc, "duration",       "duration",       "0");
            appendCopyColumn(db, oldFound, colsNew, colsSrc, "frequency",      "frequency",      "0");
            appendCopyColumn(db, oldFound, colsNew, colsSrc, "pulseWidth",     "pulseWidth",     "0");
            appendCopyColumn(db, oldFound, colsNew, colsSrc, "segmentRepeat",  "segmentRepeat",  "0");
            appendCopyColumn(db, oldFound, colsNew, colsSrc, "voltage",        "voltage",        "0");

            db.execSQL("INSERT INTO `" + T_NEW + "` (" + colsNew + ") " +
                    "SELECT " + colsSrc + " FROM `" + oldFound + "`");
            db.execSQL("DROP TABLE `" + oldFound + "`");
            return;
        }

        ensureColumn(db, T_NEW, "name",          "TEXT",    null);
        ensureColumn(db, T_NEW, "waveform",      "TEXT",    null);
        ensureColumn(db, T_NEW, "block",         "INTEGER", "0");
        ensureColumn(db, T_NEW, "current",       "INTEGER", "0");
        ensureColumn(db, T_NEW, "duration",      "INTEGER", "0");
        ensureColumn(db, T_NEW, "frequency",     "INTEGER", "0");
        ensureColumn(db, T_NEW, "pulseWidth",    "INTEGER", "0");
        ensureColumn(db, T_NEW, "segmentRepeat", "INTEGER", "0");
        ensureColumn(db, T_NEW, "voltage",       "INTEGER", "0");
    }

    private static void createStimProfilesTable(SupportSQLiteDatabase db, String table) {
        db.execSQL(
                "CREATE TABLE IF NOT EXISTS `" + table + "` (" +
                        "`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, " +
                        "`name` TEXT, " +
                        "`waveform` TEXT, " +
                        "`block` INTEGER NOT NULL DEFAULT 0, " +
                        "`current` INTEGER NOT NULL DEFAULT 0, " +
                        "`duration` INTEGER NOT NULL DEFAULT 0, " +
                        "`frequency` INTEGER NOT NULL DEFAULT 0, " +
                        "`pulseWidth` INTEGER NOT NULL DEFAULT 0, " +
                        "`segmentRepeat` INTEGER NOT NULL DEFAULT 0, " +
                        "`voltage` INTEGER NOT NULL DEFAULT 0)"
        );
    }

    private static boolean tableExists(SupportSQLiteDatabase db, String table) {
        Cursor c = db.query("SELECT name FROM sqlite_master WHERE type='table' AND name=?", new Object[]{table});
        try { return c.moveToFirst(); } finally { c.close(); }
    }

    private static boolean columnExists(SupportSQLiteDatabase db, String table, String column) {
        Cursor c = db.query("PRAGMA table_info(`" + table + "`)");
        try {
            int nameIdx = c.getColumnIndex("name");
            while (c.moveToNext()) {
                if (column.equalsIgnoreCase(c.getString(nameIdx))) return true;
            }
            return false;
        } finally { c.close(); }
    }

    private static void ensureColumn(SupportSQLiteDatabase db,
                                     String table,
                                     String column,
                                     String typeSQL,
                                     String defaultValue) {
        if (!columnExists(db, table, column)) {
            String def = (defaultValue == null) ? "" : (" DEFAULT " + defaultValue);
            db.execSQL("ALTER TABLE `" + table + "` ADD COLUMN `" + column + "` " + typeSQL + def);
        }
    }

    private static void appendCopyColumn(SupportSQLiteDatabase db,
                                         String tableOld,
                                         StringBuilder colsNew,
                                         StringBuilder colsSrc,
                                         String colNew,
                                         String colOld,
                                         String fallbackSQLLiteral) {
        if (columnExists(db, tableOld, colOld)) {
            if (colsNew.length() > 0) { colsNew.append(", "); colsSrc.append(", "); }
            colsNew.append('`').append(colNew).append('`');
            colsSrc.append('`').append(colOld).append('`');
        } else {
            if (colsNew.length() > 0) { colsNew.append(", "); colsSrc.append(", "); }
            colsNew.append('`').append(colNew).append('`');
            colsSrc.append(fallbackSQLLiteral);
        }
    }
}
